<?php
declare (strict_types=1);

namespace app\Api\controller;

use app\validate\Active as ActiveValidate;
use DateInterval;
use DatePeriod;
use DateTime;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Exception;
use think\facade\Config;
use think\facade\Db;
use think\Request;
use think\Response;
use WeChat\Mini;

class Active
{
    const TABLE_NAME = 'active';
    protected ActiveValidate $validate;

    public function __construct()
    {
        $this->validate = new ActiveValidate();
    }

    /**
     * 显示资源列表
     *
     * @return Response
     */
    public function index(Request $request)
    {
        //
        $params = $request->get();
        $page = (int)$params['pageNum'];
        $pageSize = (int)$params['pageSize'];
        $cache = $request->cache;
        $condition = array();
        $query = Db::name(self::TABLE_NAME)->alias('active');
        // 判断是平台管理员还是代理账号
        if ($cache['type'] != 1) {
            $condition[] = ['user_id', '=', $cache['id']];
        }
        if (isset($params['keywords']) && !empty($params['keywords'])) {
            $condition[] = ['name', 'like', '%' . $params['keywords'] . '%'];
        }
        if (isset($params['status'])) {
            $condition[] = ['status', '=', $params['status']];
        }
        $field = ["active.*", Db::raw("FROM_UNIXTIME(active.create_time, '%Y-%m-%d %H:%i:%s') AS createTime")];
        try {
            $paginate = $query->where($condition)->field($field)->paginate(['page' => $page, 'list_rows' => $pageSize]);
            $list = $paginate->items();

            foreach ($list as $index => $item) {
                $examiner = Db::name('examiner')->where('id', 'in', json_decode($item['examiner'], true))->field('id,name,phone')->select()->toArray();

                $list[$index]['examiner'] = [...$examiner];
            }
            return success([
                'total' => $paginate->total(),
                'list' => $list,
                'current_page' => $paginate->currentPage(),
                'last_page' => $paginate->lastPage(),
            ]);
        } catch (DbException $e) {
            return error([], 9002, $e->getMessage());
        }
    }

    /**
     * 显示创建资源表单页.
     *
     * @param Request $request
     * @return Response
     * @throws DbException
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     */
    public function create(Request $request): Response
    {
        //
        $cache = $request->cache;
        $query = Db::name(self::TABLE_NAME);
        // 如果不是超管
        if ($cache['type'] != 1) {
            $query->where('user_id', '=', $cache['id']);
        }
        // 判断是平台管理员还是代理账号
        $field = "id as value,name as label";
        $list = $query->order('id desc')->field($field)->select();

        return success($list);
    }

    /**
     * 保存新建的资源
     *
     * @param Request $request
     * @return Response
     */
    public function save(Request $request): Response
    {
        $cache = $request->cache;
        $params = $request->post();
        $this->validate = new ActiveValidate();
        $config = Config::get('database');
        // 获取表前缀
        $tablePrefix = $config['connections'][$config['default']]['prefix'];
        // 进行字段校验
        if (!$this->validate->scene('insert')->check($params)) {
            return error([], 9001, $this->validate->getError());
        } else {
            // 开启事务
            Db::startTrans();
            try {
                // 拼接活动数据
                $time = time();
                $insertData = [
                    ...$params,
                    'create_time' => $time,
                    'update_time' => $time,
                    'user_id' => $cache['id'],
                    'examiner' => json_encode($params['examiner'])
                ];
                $insertData['status'] = 1;
                $result = Db::name('active')->insertGetId($insertData);
                if ($result !== false) {
                    Db::commit();
                    writeLogToDb('创建活动成功', $cache['id'], 1, json_encode($params));
                    return success([], 0, '创建活动成功');
                } else {
                    throw new \think\Exception('录入数据失败');
                }
            } catch (\Exception $e) {
                Db::rollback();
                writeLogToDb('创建活动失败', $cache['id'], 1, $e->getMessage() . '//params:' . json_encode($params));
                return error($e->getMessage(), 9005, '创建活动失败');
            }
        }
    }

    /**
     * 显示指定的资源
     *
     * @param $id
     * @return Response
     */
    public function read($id): Response
    {
        //
        $field = ["active.*"];
        $active = Db::name(self::TABLE_NAME)->alias('active')->field($field)->find($id);
        return success($active);
    }

    /**
     * 显示编辑资源表单页.
     *
     * @param int $id
     * @return Response
     */
    public function edit($id)
    {
        //
    }

    /**
     * 保存更新的资源
     *
     * @param Request $request
     * @param int $id
     * @return Response
     */
    public function update(int $id, Request $request,): Response
    {
        //
        $cache = $request->cache;
        $params = $request->post();
        $this->validate = new ActiveValidate();
        // 进行字段校验
        if (!$this->validate->scene('insert')->check($params)) {
            return error([], 9001, $this->validate->getError());
        } else {
            try {
                // 拼接活动数据
                $time = time();
                $insertData = [
                    ...$params,
                    'update_time' => $time,
                    'user_id' => $cache['id'],
                    'examiner' => json_encode($params['examiner'])
                ];
                $result = Db::name('active')->save($insertData);
                if ($result !== false) {
                    writeLogToDb('修改活动成功', $cache['id'], 1, json_encode($params));
                    return success([], 0, '修改活动成功');
                } else {
                    throw new \think\Exception('录入数据失败', 9006);
                }
            } catch (\Exception $e) {
                writeLogToDb('修改活动失败', $cache['id'], 1, $e->getMessage() . '//params:' . json_encode($params));
                return error([], $e->getCode() ?: 9005, $e->getMessage());
            }
        }
    }

    /**
     * 删除指定资源
     *
     * @param int $id
     * @return Response
     */
    public function delete($id)
    {
        //
    }

    /** 设置活动配置
     * @param Request $request
     * @return Response
     */
    public function setConfig(Request $request): Response
    {
        $params = $request->post();
        $cache = $request->cache;
        try {
            //校验参数
            if (!$this->validate->scene('config')->check($params)) {
                throw new Exception($this->validate->getError());
            }
            $time = time();
            $saveData = [
                'active_id' => $params['active_id'],
                'period' => implode(',', $params['period']),
                'place_num' => $params['place_num'],
                'timePeriod_1' => implode(',', $params['timePeriod_1']),
                'timePeriod_2' => implode(',', $params['timePeriod_2']),
                'timePeriod_3' => implode(',', $params['timePeriod_3']),
                'timeline_1' => $params['timeline_1'],
                'timeline_2' => $params['timeline_2'],
                'timeline_3' => $params['timeline_3'],
                'unlock' => $params['unlock'],
                'lock' => $params['lock'],
                'create_time' => $time,
                'update_time' => $time
            ];
            if (isset($params['id']) && !empty($params['id'])) {
                $saveData['id'] = $params['id'];
            }
            //  通过校验后 进行时间段分配
            foreach ($params['period'] as $period) {
                // 获取指定时间段的配置参数
                $timePeriod = $params['timePeriod_' . $period];
                $timeline = $params['timeline_' . $period];
                $startDate = new DateTime($timePeriod[0]);
                $endDate = new DateTime($timePeriod[1]);
                try {
                    $saveData['timePeriod_' . $period . '_text'] = json_encode($this->splitTimePeriod($startDate, $endDate, 'PT' . $timeline . 'M'));
                } catch (\Exception $e) {
                    throw new Exception($e->getMessage());
                }
            }
            $saveResult = Db::name('active_config')->save($saveData);
            if ($saveResult !== false) {
                writeLogToDb('活动配置设置成功', $cache['id'], 1, ['data' => $saveData]);
                return success([], 0, '活动配置设置成功');
            } else {
                throw new Exception('活动配置设置失败');
            }

        } catch (\Exception $e) {
            writeLogToDb('编辑活动配置失败', $cache['id'], 1, ['message' => $e->getMessage(), 'params' => $params]);
            return error([], 9006, $e->getMessage());
        }
    }

    /**
     * 查询配置
     * @param int $id
     * @return Response
     */
    public function getConfig(int $id): Response
    {
        try {
            $data = Db::name('active_config')->where('active_id', '=', $id)->find();
            if ($data != null) {
                $data['period'] = array_map('intval', explode(',', $data['period']));
                $data['timePeriod_1'] = $data['timePeriod_1'] ? array_map(function ($date) {
                    return '2024-01-01 ' . $date . ':00';
                }, explode(',', $data['timePeriod_1'])) : [];
                $data['timePeriod_2'] = $data['timePeriod_2'] ? explode(',', $data['timePeriod_2']) : [];
                $data['timePeriod_3'] = $data['timePeriod_3'] ? explode(',', $data['timePeriod_3']) : [];

            }
            return success($data, 0);

//
        } catch (\Exception $e) {
            return error([], 9005, $e->getMessage());
        }
    }

    /** 把时间按照指定时长分割为时间段
     * @param $start
     * @param $end
     * @param $duration
     * @return array
     * @throws \Exception
     */
    private function splitTimePeriod($start, $end, $intervalSpec): array
    {

        $interval = new DateInterval($intervalSpec);

        // 初始化结果数组
        $timeSegments = [];

        // 循环遍历时间段
        $current = clone $start; // 复制开始时间，以免修改原对象
        while ($current < $end) {
            $endTime = clone $current;
            $endTime->add($interval); // 添加时间间隔到当前时间

            // 确保结束时间不超过最终的结束时间
            if ($endTime > $end) {
                $endTime = $end;
            }

            // 将时间段保存到数组
            $timeSegments[] = $current->format('H:i') . ' - ' . $endTime->format('H:i');

            // 移动到下一个时间段
            $current = $endTime;
        }
        return $timeSegments;
    }

    public function getDate(int $id)
    {
        $activeData = Db::name('active')->find($id);
        if ($activeData) {
            try {
                $date = $this->splitTimePeriodDay(new DateTime($activeData['start_time']), new DateTime($activeData['end_time']));
                return success($date);
            } catch (\Exception $e) {
                return error([], 9006, $e->getMessage());
            }
        } else {
            return error([], 9005, '非法操作');
        }
    }

    private function splitTimePeriodDay($start, $end): array
    {
        // 定义时间间隔
        $interval = new DateInterval('P1D'); // P1D 表示 1 天

        // 创建一个日期周期，包含起始日期和结束日期之间的所有日期
        $period = new DatePeriod($start, $interval, $end);
        $timeSegments = [];
        // 遍历日期周期并输出每个日期
        foreach ($period as $date) {
//            echo $date->format('Y-m-d') . PHP_EOL;
            $timeSegments[] = $date->format('Y-m-d');
        }
        return $timeSegments;
    }

    public function createQRCode(int $id, Request $request)
    {
        $cache = $request->cache;
        try {
            $activeData = Db::name(self::TABLE_NAME)->find($id);
            $Mini = new Mini();
            $examineePath = $activeData['type'] == 1 ? 'pages/guide/recite/index' : 'pages/guide/direct/index';
            $examinerPath = 'pages/exam/list/index';
            $examineeUrl = $Mini->createQRCode('id=' . $id, $examineePath);
            $examinerUrl = $Mini->createQRCode('id=' . $id, $examinerPath);
            if (!$examineeUrl || !$examinerUrl) {
                throw new Exception('生成二维码失败', 9008);
            }
            $updateData = [
                'id' => $id,
                'examiner_share_img' => str_replace('-internal', '', $examinerUrl),
                'examinee_share_img' => str_replace('-internal', '', $examineeUrl)
            ];
            $update = Db::name(self::TABLE_NAME)->update($updateData);
            if ($update !== false) {
                return success(['examiner_share_img' => $examinerUrl,
                    'examinee_share_img' => $examineeUrl]);
            } else {
                throw new Exception('二维码存储失败', 9007);
            }
//            return $activeData;
        } catch (\Exception $e) {
            writeLogToDb('生成分享码失败', $cache['id'], 1, $e->getMessage());
            return error([], $e->getCode() ?: 9006, $e->getMessage());
        }

    }

    /**
     * 根据id获取 正常考试的压缩视频地址
     * @param int $id
     * @param Request $request
     * @return Response
     */
    public function getFiles(int $id, Request $request):Response
    {
        try {
            $cache = $request->cache;
            // 查询申报信息
            $active = Db::name(self::TABLE_NAME)->find($id);
            if (strtotime($active['end_time']) > time()) {
                throw new Exception('本场考级尚未结束，无法下载整场视频');
            }

            $log = Db::name('download_log')->where(['active_id' => $id, 'user_id' => $cache['id']])->count();
            if ($log < $active['down_max_times']) {
                if (!empty($active['zip_url'])){
                    return success(['url' => $active['zip_url']]);
                }else {
                    $zip = $this->compressOssFiles($id);
                    if(!$zip){
                        throw new Exception('文件获取失败',9004);
                    }else{
                        return success(['url' => $zip]);
                    }
                }
            } else {
                throw new Exception('已达最大下载次数，请联系平台管理员');
            }
        } catch (\Exception $e) {
            return error($e->getMessage(), $e->getCode() ?: 9006, $e->getMessage());
        }
    }
    /**
     * 调用压缩oss 上的目录文件夹
     * @return void
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    private  function compressOssFiles($id): bool|string
    {
        $condition = [
            'active_id'=>$id
        ];
        // 查询出已经结束并且压缩文件地址为null的考试信息
        $active = Db::name('active')-find($id);


            $fileInfo = [
                "bucket" => "cdfherp",
                "source-dir" => "examinee/video/".$active['code'].'/',
            ];
            $result=$this->sendCurl(json_encode($fileInfo));
            if($result===false){
                writeLogToDb('申报管理',1,1,['msg'=>'创建压缩文件失败','data'=>$active]);
                return false;
            }
            $zipUrl = "https://cdfherp.oss-cn-beijing.aliyuncs.com/output/".$result['requestId'].'.zip';
            $update = Db::name('active')->update(['zip_url'=>$zipUrl,'id'=>$active['id']]);
            if($update!==false){
                writeLogToDb('申报管理',1,1,['msg'=>'视频文件压缩成功','url'=>$zipUrl,'data'=>$active]);
                return $zipUrl;
            }else{
                writeLogToDb('申报管理',1,1,['msg'=>'视频文件压缩失败','data'=>$active]);
                return false;
            }

    }
}
